﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Net.Sockets;
using System.Net;

namespace klient {
    /// <summary>
    /// Interpretuje tekstowe polecenia, wykonuje operacje na kliencie i zwraca rezultat.
    /// </summary>
    class CommandInterpreter {
        /// <summary>
        /// Klient na którym wykonywane są operacje.
        /// </summary>
        private Client client;

        /// <summary>
        /// Tworzy instancję obiektu interpretującego tekstowe polecenia dla klienta.
        /// </summary>
        /// <param name="client">Klient, na którym wykonywane będą operacje.</param>
        public CommandInterpreter(Client client) {
            this.client = client;
        }
        /// <summary>
        /// Wykonuje operację na kliencie na podstawie podanego polecenia tekstowego.
        /// </summary>
        /// <param name="command">Polecenie do wykonania w formie tekstowej.</param>
        /// <returns>Odpowiedź klienta na polecenie.</returns>
        public String ExecuteCommand(String command) {
            string lowercaseCommand = command.ToLower();
            if (lowercaseCommand.StartsWith("send ")) {
                return CmdSend(lowercaseCommand.Remove(0, 5));
            }
            else if (lowercaseCommand.StartsWith("sendfile ")) {
                return CmdSendFile(lowercaseCommand.Remove(0, 9));
            }
            else if (lowercaseCommand == "connect") {
                return CmdConnect();
            }
            else if (lowercaseCommand == "disconnect") {
                return CmdDisconnect();
            }
            else if (lowercaseCommand == "help") {
                return CmdHelp();
            }
            else if (lowercaseCommand == "exit") {
                CmdDisconnect();
                throw new Exception("Polecenie exit");
            }
            else {
                return CmdUnknown();
            }
        }
        /// <summary>
        /// Wysyła wybrany plik.
        /// </summary>
        /// <param name="path">Ścieżka do wysyłanego pliku</param>
        /// <returns>Odpowiedź serwera na wysłane informacje.</returns>
        private string CmdSendFile(string path) {
            if (File.Exists(path)) {
                return CmdSend(File.ReadAllBytes(path));
            }
            else return "Podany plik nie istnieje.";
        }
        /// <summary>
        /// Wysyła podany łańcuch znaków.
        /// </summary>
        /// <param name="message">Tekst do wysłania.</param>
        /// <returns>Odpowiedź serwera na wysłane informacje.</returns>
        private string CmdSend(object message) {
            try {
                client.Send(message);
                string reply = (string)client.Receive();
                return "Odpowiedź serwera:\n" + reply;
            }
            catch (InvalidOperationException ex) {
                return ex.Message;
            }
            catch (SocketException) {
                client.Disconnect();
                return "Połączenie zostało przerwane przez serwer.";
            }
            catch (ArgumentNullException ex) {
                return ex.Message;
            }
        }
        /// <summary>
        /// Ustanawia połączenie z serwerem.
        /// </summary>
        /// <returns>Odpowiedź klienta na polecenie.</returns>
        private string CmdConnect() {
            try {
                if (client.Connect()) return "Połączono z serwerem " + client.IpAddress + " na porcie " + client.Port + ".";
                else return "Połączenie jest już ustanowione.";
            }
            catch (Exception ex) {
                return ex.Message;
            }
        }
        /// <summary>
        /// Zamyka połączenie z serwerem.
        /// </summary>
        /// <returns>Odpowiedź klienta na polecenie.</returns>
        private string CmdDisconnect() {
            if (client.Disconnect()) return "Połączenie zakończone.";
            else return "Połączenie jest już zamknięte.";
        }
        /// <summary>
        /// Zwraca listę dostępnych poleceń i ich składni w formie tekstowej.
        /// </summary>
        /// <returns>Lista i składnia dostępnych poleceń.</returns>
        private string CmdHelp() {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine(@"Dostępne polecenia:");
            sb.AppendLine(@"               connect - nawiązuje połączenie");
            sb.AppendLine(@"            disconnect - przerywa połączenie");
            sb.AppendLine(@"          send {tekst} - wysyła wiadomość tekstową");
            sb.AppendLine(@"    sendfile {ścieżka} - wysyła podany plik");
            sb.AppendLine(@"                  help - wyświetla dostępne polecenia");
            sb.AppendLine(@"                  exit - kończy działanie programu");
            return sb.ToString();
        }
        /// <summary>
        /// Informuje o niewłaściwym poleceniu lub jego składni.
        /// </summary>
        /// <returns>Informacja o niewłaściwej nazwie polecenia.</returns>
        private string CmdUnknown() {
            return "Niewłaściwe polecenie. \nUżyj polecenia help aby uzyskać listę poleceń i ich składnię.";
        }
    }
}
